package cn.bisoft.java.util.common;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.StreamCorruptedException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

public class ObjectUtil implements Serializable
{
	private static final long serialVersionUID = 5855066687351994401L;

	@SuppressWarnings("unchecked")
	public static final <T extends Serializable> T byteClone(T src)
	{
		try
		{
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			ObjectOutputStream out = new ObjectOutputStream(baos);
			out.writeObject(src);
			out.close();
			ByteArrayInputStream bin = new ByteArrayInputStream(baos.toByteArray());
			ObjectInputStream in = new ObjectInputStream(bin);
			Object clone = in.readObject();
			in.close();
			return (T) clone;
		}
		catch (ClassNotFoundException e)
		{
			throw new InternalError(e.toString());
		}
		catch (StreamCorruptedException e)
		{
			throw new InternalError(e.toString());
		}
		catch (IOException e)
		{
			throw new InternalError(e.toString());
		}
	}

	public static final Class<?> getComponentType(Class<?> object) throws IntrospectionException
	{
		if (object.isArray())
		{
			return object.getComponentType();
		}
		else if (Collection.class.isAssignableFrom(object))
		{
			Type genericType = object.getGenericSuperclass();
			return (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
		}
		else if (Map.class.isAssignableFrom(object))
		{
			Type genericType = object.getGenericSuperclass();
			return (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[1];
		}
		else
		{
			return object;
		}
	}

	public static final Object getPropertyValue(Object bean, String property) throws IntrospectionException,
			IllegalArgumentException, IllegalAccessException, InvocationTargetException
	{
		PropertyDescriptor pd = new PropertyDescriptor(property, bean.getClass());
		Method getMethod = pd.getReadMethod();
		return getMethod.invoke(bean);
	}

	public static List<Integer> intArrayAsList(final int[] a)
	{
		if (a == null)
		{
			return new ArrayList<Integer>();
		}
		else
		{
			return new AbstractList<Integer>()
			{
				@Override
				public Integer get(int index)
				{
					return new Integer(a[index]);
				}

				public Integer set(int index, Integer o)
				{
					int oldVal = a[index];
					a[index] = ((Integer) o).intValue();
					return new Integer(oldVal);
				}

				@Override
				public int size()
				{
					return a.length;
				}
			};
		}
	}
	
}
